package top.kpromise.tree.service_imp;

import org.springframework.stereotype.Service;
import top.kpromise.tree.exception.ErrorCode;
import top.kpromise.tree.exception.RunTimeParamsException;
import top.kpromise.tree.mapper.generated.TreeMapper;
import top.kpromise.tree.mapper.tree.ITreeMapper;
import top.kpromise.tree.model.sql.Tree;
import top.kpromise.tree.service.TreeService;
import top.kpromise.tree.utils.DateUtils;
import top.kpromise.tree.utils.SnowflakeIdWorker;

import java.util.Date;

@Service
public class TreeServiceImp implements TreeService {

    private final TreeMapper mapper;
    private final ITreeMapper iTreeMapper;

    public TreeServiceImp(TreeMapper treeMapper, ITreeMapper iTreeMapper) {
        mapper = treeMapper;
        this.iTreeMapper = iTreeMapper;
    }

    @Override
    public int insert(Tree tree) {
        Date now = DateUtils.currentDate();
        tree.setUpdateAt(now);
        tree.setCreatedAt(now);
        tree.setNodeId(SnowflakeIdWorker.generateId());
        if (tree.getParentId() == null) {
            tree.setLft(1);
            tree.setRgt(2);
            tree.setDeep(1);
            return mapper.insertSelective(tree);
        }
        return insertToParent(tree);
    }

    private int insertToParent(Tree tree) {
        Tree parent = selectByNodeId(tree.getParentId());
        if (parent == null) throw new RunTimeParamsException(ErrorCode.PARENT_NOT_EXISTS);
        updateLeftAndRightValue(2, parent.getRgt() - 1, parent.getTreeType());
        tree.setLft(parent.getRgt());
        tree.setRgt(tree.getLft() + 1);
        tree.setDeep(parent.getDeep() + 1);
        return mapper.insertSelective(tree);
    }

    private void updateLeftAndRightValue(int value, int begin, int treeType) {
        updateLftValue(value, begin, treeType);
        updateRgtValue(value, begin, treeType);
    }

    @Override
    public int updateLftValue(int value, int begin, int treeType) {
        return iTreeMapper.updateLftValue(value, begin, treeType);
    }

    @Override
    public int updateRgtValue(int value, int begin, int treeType) {
        return iTreeMapper.updateRgtValue(value, begin, treeType);
    }

    @Override
    public int update(Tree tree) {
        tree.setUpdateAt(DateUtils.currentDate());
        return mapper.updateByPrimaryKeySelective(tree);
    }

    @Override
    public Tree selectByNodeId(String nodeId) {
        return mapper.selectByPrimaryKey(nodeId);
    }

    @Override
    public int deleteByNodeId(String nodeId) {
        Tree tree = selectByNodeId(nodeId);
        int childCount = childCount(tree.getLft(), tree.getRgt()) + 1;
        updateLftValue(childCount * 2, tree.getLft(), tree.getTreeType());
        return mapper.deleteByPrimaryKey(nodeId);
    }

    @Override
    public int childCount(int lft, int rgt) {
        return iTreeMapper.childCount(lft, rgt);
    }
}
